%%%-------------------------------------------------------------------
%%% @author Rain
%%% @copyright (C) 2022, <COMPANY>
%%% @doc
%%% @end
%%%-------------------------------------------------------------------
-module(gate_recv_svr).

-export([start_recv_svr/1]).

%%% Header:4bytes BinMsgLen + 4bytes MsgId Content: BinMsgLen: BinMsg)
-define(HEADER_SIZE, 8).

start_recv_svr(Sock) ->
    Pid = erlang:spawn(fun recv_pack/0),
    gen_tcp:controlling_process(Sock, Pid),
    Pid ! {start_sock_recv, Sock},
    ok.

get_route_pid() ->
    get(route_pid).

set_route_pid(Pid) ->
    put(route_pid, Pid).

recv_pack() ->
    receive
        {start_sock_recv, Sock} ->
            gate_util:set_process_sock(Sock),
            async_recv(),
            {ok, RoutePid} = gate_route_svr:start_link(Sock),
            set_route_pid(RoutePid),
            recv_pack(<<>>, Sock);
        _ ->
            recv_pack()
    end.

recv_pack(PackBuffer, Sock) ->
    receive
        {inet_async, Sock, _Ref, {ok, Pack}} ->
            PackBuffer1 = <<PackBuffer/binary, Pack/binary>>,
            PackBuffer2 = recv_pack1(PackBuffer1),
            async_recv(),
            recv_pack(PackBuffer2, Sock);
        {inet_async, _, _, {error, closed}} ->
            io:format("~p [SOCK_CLOSED] NOTICE_ROUTE ~p ~n",[self(), get(route_pid)]),
            sock_lost_to_router("Sock Closed");
        {'EXIT', Sock, Reason} ->
            io:format("~p [SOCK_ERR] NOTICE_ROUTE ~p ~n",[self(), get(route_pid)]),
            sock_lost_to_router(Reason);
        _ ->
            pass
    end.


recv_pack1(PackBuffer) ->
    PackBufferSize = erlang:byte_size(PackBuffer),
    case PackBufferSize < ?HEADER_SIZE of
        true ->
            PackBuffer;
        _ ->
            case PackBuffer of
                <<BinMsgSize:32, MsgId:32, Left/binary>> ->
                    LeftSize = erlang:byte_size(Left),
                    case LeftSize < BinMsgSize of
                        true ->
                            PackBuffer;
                        _ ->
                            <<BinMsg:BinMsgSize/binary, PackBuffer1/binary>> = Left,
                            Content = msg_proto:bin_msg_to_content(BinMsg),
                            msg_to_router(MsgId, Content),
                            PackBuffer1
                    end
            end
    end.

msg_to_router(MsgId, Content) ->
    get_route_pid() ! {from_client_msg, [MsgId, Content]}.

sock_lost_to_router(Reason) ->
    get_route_pid() ! {sock_lost, Reason}.

async_recv() ->
    case get(socket) of
        Sock when is_port(Sock) ->
            async_recv(Sock);
        _ ->
            pass
    end.

async_recv(Sock) ->
    case prim_inet:async_recv(Sock, 0, 60000) of
        {ok, _} ->
            ok;
        Err ->
            Reason = io_lib:format("Async Recv Err ~p ~p ~n",[Sock, Err]),
            sock_lost_to_router(Reason)
    end.

